﻿using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build.Utilities;
using UnityEngine;
using UnityEditor.AddressableAssets.Build;
using Object = UnityEngine.Object;

namespace UnityEditor.AddressableAssets
{
    public static class AddressableUtil
    {
        public static string DefaultGroupName
        {
            get
            {
                AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.Settings;
                if (aaSettings == null)
                    return null;
                return aaSettings.DefaultGroup.Name;
            }
        }

        public static void AddLabel(string label)
        {
            AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true);
            if (aaSettings == null)
                return;
            aaSettings.AddLabel(label, true);
        }

        public static void RemoveLabel(string label)
        {
            AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true);
            if (aaSettings == null)
                return;
            aaSettings.RemoveLabel(label, true);
        }

        public static bool RemoveAssetFromAddressable(string guid)
        {
            AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true);
            if (aaSettings == null)
                return false;
            if (GetAddressableEntry(guid) != null)
                aaSettings.RemoveAssetEntry(guid);
            return true;
        }

        public static bool AddAssetToAddressableGroup(string assetPath, string address = null, string groupName = null, bool createGroup = false)
        {
            return AddAssetToAddressableGroup(assetPath, address, groupName, null, createGroup);
        }

        public static bool AddAssetToAddressableGroup(string assetPath, string address = null, string groupName = null, string label = null, bool createGroup = false)
        {
            AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true);
            if (aaSettings == null)
                return false;

            if (groupName == null)
            {
                groupName = aaSettings.DefaultGroup.Name;
            }

            var group = aaSettings.FindGroup(grp => { return grp.Name == groupName; });

            if (group == null)
                if (!createGroup)
                {
                    Debug.LogError("Group " + groupName + " need be create.");
                    return false;
                }else
                    group = aaSettings.CreateGroup(groupName, false, false, true, null, (aaSettings.GroupTemplateObjects[0] as AddressableAssetGroupTemplate).GetTypes());


            SetAaEntry(aaSettings, group, assetPath, address, label, true);
            return true;
        }

        static void SetAaEntry(AddressableAssetSettings aaSettings, AddressableAssetGroup group, string path,
            string address, string label, bool create)
        {

            if (create && group.ReadOnly)
            {
                Debug.LogError($"Current {group.name} group is ReadOnly.  Cannot add addressable assets to it");
                return;
            }

            Undo.RecordObject(aaSettings, "AddressableAssetSettings");
            var guid = string.Empty;
            {
                var entriesAdded = new List<AddressableAssetEntry>();
                var modifiedGroups = new HashSet<AddressableAssetGroup>();
                if (GetGUIDFromPath(path, ref guid))
                {
                    if (create)
                    {
                        var e = aaSettings.CreateOrMoveEntry(guid, group, false, false);
                        e.SetAddress(address ?? path);
                        if (label != null)
                            e.SetLabel(label, true);
                        entriesAdded.Add(e);
                        modifiedGroups.Add(e.parentGroup);
                    }
                    else
                        aaSettings.RemoveAssetEntry(guid);
                }

                if (create)
                {
                    foreach (var g in modifiedGroups)
                        g.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, false, true);
                        aaSettings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entriesAdded, true, false);
                }
            }
        }

        public static bool GetGUIDFromPath(string path, ref string guid)
        {
            if (!IsPathValidForEntry(path))
                return false;
            guid = AssetDatabase.AssetPathToGUID(path);
            if (string.IsNullOrEmpty(guid))
                return false;
            return true;
        }

        public static bool IsPathValidForEntry(string path)
        {
            if (string.IsNullOrEmpty(path))
                return false;
            path = path.ToLower();
            if (path == CommonStrings.UnityEditorResourcePath ||
                path == CommonStrings.UnityDefaultResourcePath ||
                path == CommonStrings.UnityBuiltInExtraPath)
                return false;
            var ext = Path.GetExtension(path);
            if (ext == ".cs" || ext == ".js" || ext == ".boo" || ext == ".exe" || ext == ".dll")
                return false;
            return true;
        }

        public static bool GetPathAndGUIDFromTarget(Object t, out string path, ref string guid, out Type mainAssetType)
        {
            mainAssetType = null;
            path = AssetDatabase.GetAssetOrScenePath(t);
            if (!IsPathValidForEntry(path))
                return false;
            guid = AssetDatabase.AssetPathToGUID(path);
            if (string.IsNullOrEmpty(guid))
                return false;
            mainAssetType = AssetDatabase.GetMainAssetTypeAtPath(path);
            if (mainAssetType != t.GetType() && !typeof(AssetImporter).IsAssignableFrom(t.GetType()))
                return false;
            return true;
        }

        public static IEnumerable<AddressableAssetEntry> GetAllEntryInGroup(string groupName)
        {
            AddressableAssetSettings aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true);
            if (aaSettings == null)
                return null;
            
            var group = aaSettings.FindGroup(grp => { return grp.Name == groupName; });
            return group.entries;
        }

        public static AddressableAssetEntry GetAddressableEntry(string guid)
        {
            
            var aaSettings = AddressableAssetSettingsDefaultObject.Settings;
            return aaSettings.FindAssetEntry(guid);
        }

        public static AddressableAssetEntry GetAddressableEntry(Object t)
        {
            var aaSettings = AddressableAssetSettingsDefaultObject.Settings;
            var guid = string.Empty;

            if (GetPathAndGUIDFromTarget(t, out string path, ref guid, out Type mainAssetType) &&
                path.ToLower().Contains("assets") &&
                mainAssetType != null)
            {
                // Is asset
                if (!BuildUtility.IsEditorAssembly(mainAssetType.Assembly))
                {
                    if (aaSettings != null)
                    {
                        return aaSettings.FindAssetEntry(guid);
                    }
                }
            }

            return null;
        }
    }
}